package jwt.duplo.game.train {
	import Box2D.Collision.Shapes.b2CircleShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Collision.Shapes.b2Shape;
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	
	import away3dlite.core.base.Object3D;
	import away3dlite.events.Loader3DEvent;
	import away3dlite.events.MouseEvent3D;
	import away3dlite.lights.DirectionalLight3D;
	import away3dlite.loaders.*;
	import away3dlite.loaders.Loader3D;
	import away3dlite.materials.WireframeMaterial;
	import away3dlite.primitives.Cube6;
	import away3dlite.primitives.Sphere;
	
	import com.ayanray.loaders.AssetLoader;
	
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Vector3D;
	
	import jwt.duplo.game.core.GameAssetProxy;
	import jwt.duplo.game.core.GameEngine3D;
	
	import net.hires.debug.Stats;
	
	[SWF(width="960", height="570", backgroundColor="#000000", frameRate="60")]
	public class Main extends GameEngine3D {
		
		private var amount:int = 13;
		
		private const WORLD_SCALE:Number = 30;
		private var WIDTH:Number = 960;
		private var HEIGHT:Number = 570;
		
		// Physics properties
		private const GRAVITY:b2Vec2 = new b2Vec2(0.0,9.8);
		private const DO_SLEEP:Boolean = true;
		
		
		private var _blocks:Vector.<DuploBlock>;
		
		// private members
		private var _world:b2World;
		private var _boxDebug:Sprite;
		
		private var _loader:Loader3D;
		private var _block:Object3D;
		
		private var mousePVec:b2Vec2 = new b2Vec2();
		private var mouseJoint:b2MouseJoint;
		private var isMouseDown:Boolean;
		private var mouseXWorldPhys:Number;
		private var mouseYWorldPhys:Number;
		
		private var _iterations:int;
		private var _timeStep:Number;
		private var _pixelsPerMeter:Number;
		
		public function Main() {
			addEventListener(Event.ADDED_TO_STAGE, added);
		}
		
		private function added(e:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, added);
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			var assetService:GameAssetProxy = GameAssetProxy.instance;
			assetService.complete.add(onAssetsLoaded);
			assetService.send();
		}
		
		private function onAssetsLoaded():void {
			startup();
			resize(stage.stageWidth, stage.stageHeight);
			play();
		}
		
		public override function startup():void {
			
			addChild(GameAssetProxy.instance.data);
			
			super.startup();
			
			addChild(new Stats());
			
			
			
			_view.camera.focus = 10;
			_view.camera.zoom = 100;
		
			
			_blocks = new Vector.<DuploBlock>(10,true);
			
			
			// Setup Box 2D
				
			
			createWorld();
			createWalls();
			createDebugDraw();
			createBlock(0);
			createBlock(1);
			createBlock(2);
			createBlock(3);
			createBlock(4);
		
			
			setupMouseEvents();
		}
		
		private function createBlock(index:int):void
		{
			
			var body:b2Body;
			var fd:b2FixtureDef;
			
				var bodyDef:b2BodyDef = new b2BodyDef();
				bodyDef.type = b2Body.b2_dynamicBody;
				var boxDef:b2PolygonShape = new b2PolygonShape();
				fd = new b2FixtureDef();
				fd.shape = boxDef;
				fd.density = 1.0;
				// Override the default friction.
				fd.friction = 0.3;
				fd.restitution = 0.1;
				
				
				var cube:DuploBlock = new DuploBlock();
				cube.z = 30;
				_scene.addChild(cube);
				_blocks[index] = cube;
				cube.addEventListener(MouseEvent3D.MOUSE_DOWN, onBlockMouseDown);
				cube.z = index;
				//cube.scaleX = cube.scaleY = cube.scaleZ = 0.95
				
				boxDef.SetAsBox(40 / _pixelsPerMeter,46 / _pixelsPerMeter);
				bodyDef.position.Set((Math.random() * 400 + 300) / _pixelsPerMeter, (Math.random() * 150 + 50) / _pixelsPerMeter);
				bodyDef.angle = Math.random() * Math.PI;
				body = _world.CreateBody(bodyDef);
				body.CreateFixture(fd);
				
				
				cube.x = bodyDef.position.x * _pixelsPerMeter / 2;
				cube.y = bodyDef.position.y * _pixelsPerMeter / 2;
				
				
				body.SetUserData(cube)
				
			
		}
		
		private function createWorld():void {
			_world = new b2World(GRAVITY, DO_SLEEP);
			_world.SetWarmStarting(true);
			_timeStep = 1.0/30.0;
			_iterations = 10;
			_pixelsPerMeter = 30;
		}
		
		private function createWalls():void {
			var wall:b2PolygonShape = new b2PolygonShape();
			var wallBd:b2BodyDef = new b2BodyDef();
			var wallB:b2Body;
			
			//right
			/*wallBd.position.Set(WIDTH/_pixelsPerMeter, HEIGHT/2/_pixelsPerMeter);
			wall.SetAsBox(10/_pixelsPerMeter, HEIGHT/_pixelsPerMeter/2);
			wallB = _world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			
			//left
			wallBd.position.Set(0, HEIGHT/2/_pixelsPerMeter);
			wall.SetAsBox(10/_pixelsPerMeter, HEIGHT/_pixelsPerMeter/2);
			wallB = _world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);*/
			
			//bottom
			wallBd.position.Set(WIDTH / _pixelsPerMeter / 2 + .6, (HEIGHT - 95)/ _pixelsPerMeter );
			wall.SetAsBox((WIDTH -274)/_pixelsPerMeter/2, 10/_pixelsPerMeter);
			wallB = _world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
		}
		
		private function createDebugDraw():void {
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			debugSprite.mouseEnabled = false;
			addChild(debugSprite);
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(_pixelsPerMeter);
			debugDraw.SetFillAlpha(.3);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			_world.SetDebugDraw(debugDraw);
		}
		
		protected override function render(e:Event):void {
			updateMouseWorld();
			mouseDrag();
			_world.Step(_timeStep, _iterations, _iterations);
			_world.ClearForces();
			for (var bb:b2Body = _world.GetBodyList(); bb; bb = bb.GetNext()) {
				if (bb.GetUserData() is Object3D) {
					bb.GetUserData().x = bb.GetPosition().x * WORLD_SCALE - WIDTH * .5;
					bb.GetUserData().y = bb.GetPosition().y * WORLD_SCALE - HEIGHT * .5;
					bb.GetUserData().rotationZ = bb.GetAngle() * (180/Math.PI);
				}
			}
			//_world.DrawDebugData();
			super.render(e);
		}
		
		private function onBlockMouseDown(e:MouseEvent3D):void {
			_block = Object3D(e.currentTarget);
			var i:int = 5;
			while( --i > -1 ) {
				_blocks[i].z = i / 10;
			}
			_block.z = -1/10;
		}
		
		private function setupMouseEvents():void {
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		}
		private function onMouseDown(e:MouseEvent):void {
			isMouseDown = true;
		};
		
		private function onMouseUp(e:MouseEvent):void{ 
			isMouseDown = false;
		};
		
		private function updateMouseWorld():void{
			mouseXWorldPhys = mouseX/WORLD_SCALE; 
			mouseYWorldPhys = mouseY/WORLD_SCALE; 
		}
		
		private function mouseDrag():void{
			// mouse press
			if (isMouseDown && !mouseJoint){
				
				//refer to 'getBodyAtMouse()' below
				var body:b2Body = getBodyAtMouse();
				
				if (body)
				{
					var md:b2MouseJointDef = new b2MouseJointDef();
					md.bodyA = _world.GetGroundBody();
					md.bodyB = body;
					md.target = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys);
					md.maxForce = 300.0 * body.GetMass();
					md.frequencyHz = _timeStep;
					mouseJoint = _world.CreateJoint(md) as b2MouseJoint;
					
				}
			}
			

			// mouse release
			if (!isMouseDown){
				if (mouseJoint){
					_world.DestroyJoint(mouseJoint);
					mouseJoint = null;
				}
			}
			
			
			// mouse move
			if (mouseJoint)
			{
				var p2:b2Vec2 = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys);
				mouseJoint.SetTarget(p2);
			} 
		}
		
		public function getBodyAtMouse(isStaticIncluded:Boolean=false):b2Body{
			// Make a small box.
			var body:b2Body;
			
			for (var bb:b2Body = _world.GetBodyList(); bb; bb = bb.GetNext()) {
				if (bb.GetUserData() === _block) {
					return bb;
				}
			}
				
			return body;
		}
		
		public override function resize(width:int, height:int):void {
			super.resize(width, height);
			WIDTH = width;
			HEIGHT = height;
		}
	}
}